﻿#include "editor/drawing/pen.h"
#include "editor/drawing/tool.h"
#include "editor/drawing/area.h"
#include "texture.h"
#include "draw.h"

using namespace anip;
using namespace anip::editor;

struct drawing::PenTool::Impl
{
	static PreloadedTexture
		icon, 
		cursor;

	vg::Stroke* current = nullptr;

	ui::Container* panel = nullptr;

	vec2 lastPosition{};
	double lastTime = 0;
	float cursorVelocity = 0;
};

PreloadedTexture drawing::PenTool::Impl::icon("ui/penbrush.png");
PreloadedTexture drawing::PenTool::Impl::cursor("ui/arrow-cursor.png");

drawing::PenTool::PenTool():
	_pimpl(new Impl())
{
	params.velocityWidthMultiplier = kfloat::fromFunction(
		[](float x) {return 1 / sqrtf(1.0f + x); }, 0.01f, 0.0f, 3.0f);
}

Texture2D* drawing::PenTool::getIcon()
{
	return Impl::icon.get();
}

void drawing::PenTool::processCreateUI(ui::Container& c)
{
	_pimpl->panel = &c;
	params.width.createUI(c);
}

void drawing::PenTool::processDeleteUI(ui::Container& c)
{
	params.width.destroyUI(c);
}

void drawing::PenTool::drawGizmo(invec2 pos)
{
	color c = _pimpl->current == nullptr ? Colors::black : Colors::orangeRed;
	Draw::line(pos - vec2{ 10, 0 }, pos + vec2{ 10, 0 }, 2.0f, c);
	Draw::line(pos - vec2{ 0, 10 }, pos + vec2{ 0, 10 }, 2.0f, c);

	_pimpl->lastPosition = pos;
	_pimpl->lastTime = time();
}

bool drawing::PenTool::beginStroke(DrawingArea& area, 
	MouseButton btn, invec2 pos, const StylusData& data)
{
	if (_pimpl->current != nullptr) return false;
	if (btn == MouseButton::Left)
	{
		_pimpl->current = new vg::Stroke();
		Globals::currentDrawingArea
			->currentFrameGroup().primitives.push_back(_pimpl->current);
		strokePoint(area, pos, data);
		return true;
	}
	return false;
}

bool drawing::PenTool::strokePoint(DrawingArea& area, 
	invec2 pos, const StylusData& data)
{
	if (_pimpl->current == nullptr) return false;

	double time2 = time();
	_pimpl->cursorVelocity = 0.8f * _pimpl->cursorVelocity
		+ 0.2f * math::distance(_pimpl->lastPosition, pos) / (time2 - _pimpl->lastTime);

	vg::Stroke::Point p;
	p.position = pos;
	p.velocity = _pimpl->cursorVelocity;
	p.color = params.color;
	p.width = params.width.value * params.velocityWidthMultiplier[p.velocity];
	
	if (data.hasOrientation)
		p.normal = { -::cos(data.orientation), ::sin(data.orientation) };
	if (data.hasPressure)
		p.pressure = data.pressure;

	_pimpl->current->points.push_back(p);
	
	if (!data.hasOrientation)
		_pimpl->current->calcNormal();
	_pimpl->current->markEdit();

	_pimpl->lastPosition = pos;
	_pimpl->lastTime = time();

	return true;
}

bool drawing::PenTool::endStroke(DrawingArea& area)
{
	if (_pimpl->current != nullptr)
		_pimpl->current = nullptr;
	return false;
}
